#include "vector2d.h"
#include "matrix.h"

Vector2D::Vector2D() {}

Vector2D::Vector2D(const Vector2D& other) : x_(other.x_), y_(other.y_) {}

Vector2D::Vector2D(ZNumber x, ZNumber y) : x_(x), y_(y) {}

Vector2D::Vector2D(int32_t x, int32_t y) : x_(x), y_(y) {}

Vector2D::~Vector2D() {}

const ZNumber& Vector2D::X() const { return x_; }

const ZNumber& Vector2D::Y() const { return y_; }

void Vector2D::SetX(ZNumber x) { x_ = x; }

void Vector2D::SetY(ZNumber y) { y_ = y; }

void Vector2D::Set(ZNumber x, ZNumber y) {
  x_ = x;
  y_ = y;
}

void Vector2D::operator=(const Vector2D& other) {
  x_ = other.x_;
  y_ = other.y_;
}

Vector2D Vector2D::operator-(const Vector2D& other) const {
  Vector2D res;
  res.x_ = x_ - other.x_;
  res.y_ = y_ - other.y_;
  return res;
}

Vector2D Vector2D::operator-() const { return Vector2D(-x_, -y_); }

Vector2D Vector2D::operator+(const Vector2D& other) const {
  Vector2D res;
  res.x_ = x_ + other.x_;
  res.y_ = y_ + other.y_;
  return res;
}

ZNumber Vector2D::Length() const { return FloatSqrt(x_ * x_ + y_ * y_); }

ZNumber Vector2D::LengthSquare() const { return x_ * x_ + y_ * y_; }

Vector2D Vector2D::Normal() const {
  if (x_.IsZero() && y_.IsZero()) {
    return Vector2D();
  }

  auto temp = FloatSqrt(x_ * x_ + y_ * y_);

  Vector2D res;
  ZNumber value;
  res.x_ = x_ / temp;
  res.y_ = y_ / temp;
  return res;
}

Vector2D Vector2D::operator*(const ZNumber& other) const {
  Vector2D res;
  res.x_ = x_ * other;
  res.y_ = y_ * other;
  return res;
}

Vector2D Vector2D::operator/(const ZNumber& other) const {
  if (other == 0u) {
    return Vector2D();
  }

  Vector2D res;
  res.x_ = x_ / other;
  res.y_ = y_ / other;
  return res;
}

ZNumber Vector2D::operator*(const Vector2D& other) const {
  return x_ * other.y_ - other.x_ * y_;
}

bool Vector2D::operator==(const Vector2D& other) const {
  if (x_ == other.x_ && y_ == other.y_) {
    return true;
  }
  return false;
}

void Vector2D::SetRealValue(int64_t x, int64_t y) {
  x_.SetValue(x);
  y_.SetValue(y);
}

void Vector2D::Clear() {
  x_.SetValue(0);
  y_.SetValue(0);
}

bool Vector2D::IsZero() { return x_.IsZero() && y_.IsZero(); }

uint32_t Vector2D::GridX() const { return x_.ToGrid(); }

uint32_t Vector2D::GridY() const { return y_.ToGrid(); }

std::string Vector2D::Print() const {
  std::ostringstream oss;
  oss << "{" << x_.GetValue() << "," << y_.GetValue() << "}";
  return oss.str();
}

std::string Vector2D::ToString() const {
  std::ostringstream oss;
  oss << "{" << x_.ToInt() << "," << y_.ToInt() << "}";
  return oss.str();
}

bool Vector2D::operator<=(const Vector2D& other) const {
  if (X() > other.X()) {
    return true;
  } else if (X() == other.X()) {
    return Y() <= other.Y();
  }
  return false;
}

bool Vector2D::operator<(const Vector2D& other) const {
  if (X() < other.X()) {
    return true;
  } else if (X() == other.X()) {
    return Y() < other.Y();
  }
  return false;
}

ZNumber Vector2D::Dot(const Vector2D& other) const {
  return (x_ * other.x_ + y_ * other.y_);
}

Vector2D Vector2D::operator*(const Matrix2& other) const {
  Vector2D res;
  res.x_ = x_ * other.m11_ + y_ * other.m21_;
  res.y_ = x_ * other.m12_ + y_ * other.m22_;
  return res;
}
